// bzoj4027
// 题意：
// 给定一个n(<=2000000)个节点的树，每个节点有一个樱花的数量(<=1000)。
// 每个节点要时刻满足当前节点樱花数量加上儿子节点的个数不超过一个给定的数m。
// 现在你想要删除一些节点，如果删除某个节点，就把这个节点上的樱花移到父亲
// 节点上，这个节点的儿子都接到它父亲上，如果父亲节点也被删除，就移到第一个
// 未被删除的节点上。问最多可以删除多少节点。
//
// 题解：
// 考虑一个节点上的费用，就是这个节点上的樱花数目+这个节点儿子数目，
// 记做cost[i]。
// 我们发现，把一个节点i删除，相应的费用转移到父亲节点就是cost[i] - 1。
//
// 对于每个节点，我们将其儿子的cost[i] - 1按小到大，如果加到自己费用上
// 不超过m，就把这个儿子节点删除就行，这是个贪心的过程，为什么是对的呢？
//
// 每个点的费用只会在删除的时候给父亲节点造成影响。那么对于当前节点，
// 如果不选择贪心的这么把儿子的费用传过来，那么我的目的是为了尽量减少
// 这个节点的费用，以把这个节点删掉，转移给父亲（不然的话，没意义）。
//
// 但是我们发现，这样只能删除这个节点，还不如多删几个子节点，而保留当前节点呢。
//
// run: $exec < input
#include <iostream>
#include <functional>
#include <queue>
#include <vector>

int const maxn = 2000007;
int cost[maxn];
int n, m;

std::priority_queue<int, std::vector<int>, std::greater<int> > pq;
std::vector<std::vector<int> > tree;

void add_edge(int u, int v)
{
	tree[u].push_back(v);
	tree[v].push_back(u);
}

int dfs(int u, int parent)
{
	int son = 0, ret = 0;
	for (int i = 0; i < (int)tree[u].size(); i++) {
		int v = tree[u][i];
		if (v == parent) continue;
		son++;
		ret += dfs(v, u);
	}
	while (!pq.empty()) pq.pop();
	for (int i = 0; i < (int)tree[u].size(); i++) {
		int v = tree[u][i];
		if (v == parent) continue;
		pq.push(cost[v] - 1);
	}
	cost[u] += son;
	while (!pq.empty() && pq.top() + cost[u] <= m) {
		int tmp = pq.top(); pq.pop();
		cost[u] += tmp;
		ret++;
	}
	return ret;
}

int main()
{
	std::ios::sync_with_stdio(false);
	std::cin >> n >> m;
	tree.resize(n);
	for (int i = 0; i < n; i++)
		std::cin >> cost[i];
	for (int i = 0, x; i < n; i++) {
		std::cin >> x;
		for (int j = 0, y; j < x; j++) {
			std::cin >> y;
			add_edge(i, y);
		}
	}
	std::cout << dfs(0, -1) << "\n";
}

